!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

 module glc_global_grid

!BOP
! !MODULE: glc_global_grid
!
! !DESCRIPTION:
!  This module contains grid info and routines for setting up the
!  global glc grid quantities.
!  
!  This module is very simple because all we need to do is read in
!   grid size, latitude, and longitude from a file.  This information
!  is needed to receive data from the coupler and pass it to GLINT.  
!
!  Later we may have a more sophisticated, POP-like routine to set up
!  the high-resolution regional ice sheet grid(s).
!
! !REVISION HISTORY:
!  SVN:$Id: grid.F90 808 2006-04-28 17:06:38Z njn01 $
!  Adapted by William Lipscomb from grid.F90 in POP
!
! !USES:

   use glc_kinds_mod
   use glc_communicate
   use glc_constants
   use glc_exit_mod
   use glint_global_grid
   
   use shr_sys_mod, only : shr_sys_flush
   use shr_file_mod, only : shr_file_getunit, shr_file_freeunit

   implicit none
   private
   save

   public  :: init_glc_grid, glc_landmask, glc_landfrac, glc_grid

! !PUBLIC DATA MEMBERS:

   type(global_grid) ::   &
      glc_grid        ! info (nx, ny, lat, lon, area) for coupling grid (indexed S to N)

   integer, dimension(:,:), allocatable ::  &
      glc_landmask          ! landmask = 1 where global grid has valid data from CLM
                            ! (i.e., gridcells with nonzero land area)

   real(r8), dimension(:,:), allocatable ::  &
      glc_landfrac          ! land fraction, between 0 and 1
 
!EOP
!BOC
!-----------------------------------------------------------------------
!
!  module private data
!
!-----------------------------------------------------------------------

   character (char_len) ::  &
      horiz_grid_opt       ,&! option for getting horiz grid info
      mask_varname         ,&! variable name for landmask
      frac_varname           ! variable name for landfrac

   character (char_len_long) ::  &
      horiz_grid_file        ! input file for reading horiz grid info

!EOC
!***********************************************************************

 contains

!***********************************************************************

!BOP
! !IROUTINE: init_glc_grid
! !INTERFACE:

 subroutine init_glc_grid

! !DESCRIPTION:
!  Initialize grid quantities
!
! !REVISION HISTORY:
!  same as module

!EOP
!BOC
!-----------------------------------------------------------------------
!
!  local variables
!
!-----------------------------------------------------------------------

   namelist /grid_nml/ horiz_grid_opt, horiz_grid_file, mask_varname, frac_varname

   integer (int_kind) :: &
      nml_error           ! namelist i/o error flag

!-----------------------------------------------------------------------
!
!  read input namelist for grid setup options
!
!-----------------------------------------------------------------------

   horiz_grid_opt       = 'unknown_horiz_grid_opt'
   horiz_grid_file      = 'unknown_horiz_grid_file'
   mask_varname         = 'unknown mask varname'
   frac_varname         = 'unknown frac varname'

   if (my_task == master_task) then
      open (nml_in, file=nml_filename, status='old',iostat=nml_error)
      if (nml_error /= 0) then
         nml_error = -1
      else
         nml_error =  1
      endif
      do while (nml_error > 0)
         read(nml_in, nml=grid_nml,iostat=nml_error)
      end do
      if (nml_error == 0) close(nml_in)
   endif

   if (nml_error /= 0) then
      call exit_glc(sigAbort,'ERROR reading grid_nml')
   endif

   if (my_task == master_task) then
      write(stdout,blank_fmt)
      write(stdout,ndelim_fmt)
      write(stdout,blank_fmt)
      write(stdout,*) ' Grid:'
      write(stdout,blank_fmt)
      write(stdout,*) ' grid_nml namelist settings:'
      write(stdout,blank_fmt)
      write(stdout, grid_nml)
   endif

!-----------------------------------------------------------------------
!
!  output grid setup options to log file
!
!-----------------------------------------------------------------------

   if (my_task == master_task) then
      write(stdout,delim_fmt)
      write(stdout,blank_fmt)
      write(stdout,'(a13)') ' Grid options'
      write(stdout,blank_fmt)
   endif

!-----------------------------------------------------------------------
!
!  set up horizontal grid
!
!-----------------------------------------------------------------------

   select case (horiz_grid_opt)
   case ('internal')
      if (my_task == master_task) then
         write(stdout,'(a36)') ' Creating horizontal grid internally'
      endif
      call horiz_grid_internal
   case ('file')
      if (my_task == master_task) then
         write(stdout,*) 'Reading horizontal grid from file:', &
                          trim(horiz_grid_file)
      call shr_sys_flush(stdout)
      endif
      call read_horiz_grid(horiz_grid_file, mask_varname, frac_varname)
   case default
      call exit_glc(sigAbort,'ERROR: unknown horizontal grid option')
   end select

!-----------------------------------------------------------------------
!EOC

 call flushm (stdout)

 end subroutine init_glc_grid

!***********************************************************************
!BOP
! !IROUTINE: horiz_grid_internal
! !INTERFACE:

 subroutine horiz_grid_internal

! !DESCRIPTION:
!  Creates a lat/lon grid with equal spacing in each direction
!
! !REVISION HISTORY:
!  same as module

!EOP
!BOC
!-----------------------------------------------------------------------
!
!  local variables
!
!-----------------------------------------------------------------------

   integer (int_kind) :: &
      i,j,ig,jg,jm1,n    ! dummy counters

   real (r8) :: &
      dlat, dlon,       &! lat/lon spacing for idealized grid
      lathalf,          &! lat at T points
      xdeg               ! temporary longitude variable

!lipscomb - TO DO - Enable internal grid generation, if desired
   call exit_glc(sigAbort, 'Internal grid generation not yet enabled')

!-----------------------------------------------------------------------
!EOC

 end subroutine horiz_grid_internal

!***********************************************************************
!BOP
! !IROUTINE: read_horiz_grid
! !INTERFACE:

 subroutine read_horiz_grid(horiz_grid_file, mask_varname, frac_varname)

! !DESCRIPTION:
!  Reads horizontal grid, landmask, and landfrac from input grid file
!
! !REVISION HISTORY:
!  same as module

! !USES:

   use glint_example_clim, only: read_ncdf, read_ncdf_ggrid
   use glimmer_paramets,   only: itest, jtest
   use glint_global_grid

! !INPUT PARAMETERS:

   character (*), intent(in) :: &
      horiz_grid_file  ,&! filename of file containing grid data
      mask_varname     ,&! variable name for landmask
      frac_varname       ! variable name for landfrac
!EOP
!BOC
!-----------------------------------------------------------------------
!
!  local variables
!
!-----------------------------------------------------------------------

   integer(i4) :: i, j            ! indices
   integer(i4) :: nx, ny          ! global grid dimensions

   real(r8), dimension(:,:), pointer ::  &
      landmask => null()      ,&! landmask, glc/clm grid
      landfrac => null()        ! landfrac, glc/clm grid

   real(r8) :: &
      latn, lats, lone, lonw   ! lat and lon of cell edges (radians)

!-----------------------------------------------------------------------
!
! Extract global grid and mask information from netCDF topography file.
! For now we use GLINT subroutines to do this.
!
!-----------------------------------------------------------------------

! to do - Make sure the read is done correctly
!!   call read_ncdf(horiz_grid_file, mask_varname, landmask, glc_grid)
!!   call read_ncdf(horiz_grid_file, frac_varname, landfrac, glc_grid)

   ! Initialize the grid and masks

   call read_ncdf_ggrid(horiz_grid_file, glc_grid)

   call read_ncdf(horiz_grid_file, mask_varname, landmask)
   call read_ncdf(horiz_grid_file, frac_varname, landfrac)

   nx = glc_grid%nx
   ny = glc_grid%ny

!lipscomb - GLINT assumes the grid is indexed N to S and automatically sets
!            lat_bound(1) = 90, lat_bound(ny+1) = -90.
!           Reverse that convention here.

   glc_grid%lat_bound(1)    = -90._r8
   glc_grid%lat_bound(ny+1) =  90._r8

   do i = 1, nx
      if (glc_grid%lon_bound(i) < 0._r8)   &
          glc_grid%lon_bound(i) = glc_grid%lon_bound(i) + 360._r8
   enddo
 
   ! Set glc_landmask and glc_landfrac

   allocate(glc_landmask(nx,ny))
   glc_landmask(:,:) = nint(landmask(:,:))

   allocate(glc_landfrac(nx,ny))
   glc_landfrac(:,:) = landfrac(:,:)

   ! Make sure glc_landmask and glc_landfrac have expected values.

   do j = 1, ny
   do i = 1, nx
 
      if (glc_landmask(i,j) /= 0 .and. glc_landmask(i,j) /= 1) then
         write(stdout,*) 'landmask has invalid value: i, j, landmask =', i, j, glc_landmask(i,j)
         call exit_glc(sigAbort, 'invalid landmask value')
      endif

      if (glc_landfrac(i,j) < 0._r8 .or. glc_landfrac(i,j) > 1._r8) then
         write(stdout,*) 'landfrac has invalid value: i, j, landfrac =', i, j, glc_landfrac(i,j)
         call exit_glc(sigAbort, 'invalid landfrac value')
      endif

   enddo
   enddo

   ! compute grid cell area
   ! Note: Global grid is indexed from south to north, so the south edge of cell (i,j+1)
   !       is the north edge of cell (i,j)

   allocate(glc_grid%box_areas(nx,ny))

   do j = 1, ny
   do i = 1, nx

      latn = glc_grid%lat_bound(j+1) * pi/180._r8   ! degrees to radians
      lats = glc_grid%lat_bound(j)   * pi/180._r8
      latn = pi/2._r8 - latn  ! so lat = 0 at NP, = pi at SP
      lats = pi/2._r8 - lats  
      lone = glc_grid%lon_bound(i+1) * pi/180._r8
      lonw = glc_grid%lon_bound(i)   * pi/180._r8
      if (lone < lonw) lone = lone + 2._r8*pi
      glc_grid%box_areas(i,j) = radius**2 * (cos(latn)-cos(lats)) * (lone-lonw)

      ! Make sure area is positive
      if (glc_grid%box_areas(i,j) <= 0._r8) then
         if (verbose) then
            write(stdout,*) 'Negative area: i, j, area =', i, j, glc_grid%box_areas(i,j)
            write(stdout,*) 'latn, lats =', latn, lats
            write(stdout,*) 'cos(latn), cos(lats) =', cos(latn), cos(lats)
            write(stdout,*) 'lone, lonw =', lone, lonw
            write(stdout,*) 'latb(j), latb(j+1) =', glc_grid%lat_bound(j), &
                                                    glc_grid%lat_bound(j+1)
            write(stdout,*) 'lonb(i), lonb(i+1) =', glc_grid%lon_bound(i), &
                                                    glc_grid%lon_bound(i+1)
         endif
         call exit_glc(sigAbort, 'Negative gridcell area on glc grid')
      endif

   enddo
   enddo

   if (verbose .and. my_task==master_task) then
      write(stdout,*) ''
      write(stdout,*) 'Horizontal grid:'
      write(stdout,*) 'nx =', nx
      write(stdout,*) 'ny =', ny
!      write(stdout,*) 'lats =', glc_grid%lats(:)  
!      write(stdout,*) 'lons =', glc_grid%lons(:)
!      write(stdout,*) 'lat_bound =', glc_grid%lat_bound(:)
!      write(stdout,*) 'lon_bound =', glc_grid%lon_bound(:)
      write(stdout,*) ''
      i = itest
      j = jtest
      write(stdout,*) 'Test point, i, j, =', itest, jtest
      write(stdout,*) 'lat, lon =', glc_grid%lats(j), glc_grid%lons(i)
      write(stdout,*) 'area =', glc_grid%box_areas(i,j)
      write(stdout,*) 'landmask =', glc_landmask(i,j)
      write(stdout,*) 'landfrac =', glc_landfrac(i,j)
      write(stdout,*) 'frac of earth =', glc_grid%box_areas(i,j) / (4._r8*pi*radius*radius)
      write(stdout,*) 'Leaving read_horiz_grid'
      call shr_sys_flush(stdout)
   endif

!-----------------------------------------------------------------------
!EOC

 end subroutine read_horiz_grid

!***********************************************************************

 end module glc_global_grid

!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

